package com.falcon.tools.service;

import com.falcon.authority.api.IApiApi;
import com.falcon.authority.domain.dos.ApiDTO;
import com.falcon.authority.domain.po.ApiPO;
import com.falcon.core.utils.UriUtil;
import com.falcon.tools.domain.ApiSyncResult;
import com.falcon.tools.domain.ControllerMeta;
import com.falcon.tools.domain.ControllerMethodMeta;
import com.falcon.tools.parse.IControllerScanner;
import com.swan.core.utils.str.NameUtil;
import com.swan.mybatis.condition.Condition;
import com.swan.mybatis.condition.OpType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author zongf
 * @date 2024-02-19
 **/
@Slf4j
@Service
public class ApiMetaService implements IApiMetaService {

    @Autowired
    private IControllerScanner controllerScanner;

    @Autowired
    private IApiApi apiApi;

    @Override
    public ApiSyncResult initApi() {
        ApiSyncResult apiSyncResult = new ApiSyncResult();

        // 扫描所有的 api
        List<ControllerMeta> scanComponents = this.controllerScanner.doScan(true, true, true);

        // 先将所有的 API 标记为 删除
        this.apiApi.updateStatus(0);

        Map<String, Long> moduleMapId = new HashMap<>();
        List<String> moduleList = scanComponents.stream().map(ControllerMeta::getModuleName).distinct().sorted().toList();
        for (String module : moduleList) {
            ApiDTO moduleApi = new ApiDTO();
            moduleApi.setId(UriUtil.toUniqueId(module));
            moduleApi.setModuleName(module);
            moduleApi.setDescription(module);
            moduleApi.setRequestUri(module);
            moduleApi.setStatus(1);
            this.apiApi.saveOrUpdate(moduleApi);
            moduleMapId.put(module, moduleApi.getId());
        }

        // 更新
        scanComponents.forEach(controllerMeta -> {
            log.info("controllerMeta:{}", controllerMeta);

            // 保存 Controller
            ApiDTO controllerApiDTO = new ApiDTO();
            controllerApiDTO.setId(UriUtil.toUniqueId(controllerMeta.getRequestUri()));
            controllerApiDTO.setModuleName(controllerMeta.getSimpleName());
            controllerApiDTO.setDescription(controllerMeta.getDescription());
            controllerApiDTO.setRequestUri(controllerMeta.getRequestUri());
            controllerApiDTO.setParentId(moduleMapId.get(controllerMeta.getModuleName()));
            controllerApiDTO.setStatus(1);
            this.apiApi.saveOrUpdate(controllerApiDTO);

            // 如果为空, 表示为更新操作
            if (Objects.nonNull(controllerApiDTO.getId())) {
                apiSyncResult.setAddCnt(apiSyncResult.getAddCnt() + 1);
            } else {
                apiSyncResult.setUpdateCnt(apiSyncResult.getUpdateCnt() + 1);
            }

            // 保存方法
            for (ControllerMethodMeta controllerMethodMeta : controllerMeta.getControllerMethodMetas()) {
                ApiDTO methodApiDTO = new ApiDTO();
                methodApiDTO.setId(UriUtil.toUniqueId(controllerMethodMeta.getRequestUri()));
                methodApiDTO.setParentId(controllerApiDTO.getId());
                methodApiDTO.setName(controllerMethodMeta.getName());
                methodApiDTO.setHttpMethod(controllerMethodMeta.getHttpMethod());
                methodApiDTO.setRequestUri(controllerMethodMeta.getRequestUri());
                methodApiDTO.setDescription(controllerMethodMeta.getDescription());
                methodApiDTO.setPerms(getPerms(controllerApiDTO.getModuleName(), controllerApiDTO.getName(), methodApiDTO.getName()));
                methodApiDTO.setStatus(1);
                this.apiApi.saveOrUpdate(methodApiDTO);

                // 判断更新还是新增
                if (Objects.nonNull(methodApiDTO.getId())) {
                    apiSyncResult.setAddCnt(apiSyncResult.getAddCnt() + 1);
                } else {
                    apiSyncResult.setUpdateCnt(apiSyncResult.getUpdateCnt() + 1);
                }
            }
        });


        Condition condition = Condition.newInstance().and(ApiPO.Fields.status, OpType.equals, 0);
        int deleteCount = this.apiApi.count(condition);
        apiSyncResult.setDeleteCnt(deleteCount);

        return apiSyncResult;

    }

    private String getPerms(String moduleName, String className, String methodName){
        // 权限标识符: module:controller:method
        String first = NameUtil.firstLowercase(moduleName);
        String second = NameUtil.firstLowercase(StringUtils.substringBefore(className, "Controller"));
        String last = NameUtil.firstLowercase(methodName);
        return String.format("%s:%s:%s", first, second, last);
    }

}
